#ifndef EMAIL_VERIFICATION_H
#define EMAIL_VERIFICATION_H

#include <iostream>
#include <string>
#include <unordered_map>
#include <ctime>
#include <random>
#include <sstream>
#include <iomanip>
#include <cstring>
#include <openssl/ssl.h>
#include <openssl/err.h>
#include <openssl/bio.h>
#include <sys/socket.h>
#include <netdb.h>
#include <unistd.h>
#include "logger.hpp"

namespace zjx_im
{
// Base64编码表
static const std::string base64_chars = 
    "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
    "abcdefghijklmnopqrstuvwxyz"
    "0123456789+/";

class DMSClient {
private:
    std::string smtp_server_;
    int port_;
    std::string email_user_;
    std::string email_pass_;
    std::string sender_name_;
    SSL_CTX* ssl_ctx_;
    SSL* ssl_;

public:
    using ptr = std::shared_ptr<DMSClient>;
    DMSClient(const std::string& smtp_server, 
               int port,
               const std::string& email_user,
               const std::string& email_pass,
               const std::string& sender_name = "验证码系统")
        : smtp_server_(smtp_server), port_(port), 
          email_user_(email_user), email_pass_(email_pass),
          sender_name_(sender_name), ssl_ctx_(nullptr), ssl_(nullptr) {
        
        // 初始化OpenSSL
        SSL_library_init();
        SSL_load_error_strings();
        OpenSSL_add_all_algorithms();
    }

    ~DMSClient() {
        if (ssl_) {
            SSL_shutdown(ssl_);
            SSL_free(ssl_);
        }
        if (ssl_ctx_) {
            SSL_CTX_free(ssl_ctx_);
        }
    }

    bool sendEmail(const std::string& to_email, 
                  const std::string& to_name,
                  const std::string& subject, 
                  const std::string& body) {
        
        // 创建socket
        int sockfd = socket(AF_INET, SOCK_STREAM, 0);
        if (sockfd < 0) {
            std::cerr << "创建socket失败" << std::endl;
            return false;
        }
        
        // 解析SMTP服务器地址
        struct hostent* server = gethostbyname(smtp_server_.c_str());
        if (server == NULL) {
            std::cerr << "无法解析SMTP服务器: " << smtp_server_ << std::endl;
            close(sockfd);
            return false;
        }
        
        struct sockaddr_in serv_addr;
        memset(&serv_addr, 0, sizeof(serv_addr));
        serv_addr.sin_family = AF_INET;
        serv_addr.sin_port = htons(port_);
        memcpy(&serv_addr.sin_addr.s_addr, server->h_addr, server->h_length);
        
        // 连接SMTP服务器
        if (connect(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
            std::cerr << "连接SMTP服务器失败: " << smtp_server_ << ":" << port_ << std::endl;
            close(sockfd);
            return false;
        }
        
        std::cout << "已连接到SMTP服务器: " << smtp_server_ << std::endl;
        
        try {
            // 读取欢迎信息
            if (!smtpReadResponse(sockfd, "220")) {
                throw std::runtime_error("SMTP欢迎信息错误");
            }
            
            // EHLO
            smtpSendCommand(sockfd, "EHLO localhost\r\n");
            if (!smtpReadResponse(sockfd, "250")) {
                throw std::runtime_error("EHLO命令失败");
            }
                   
            // 发送STARTTLS命令
            smtpSendCommand(sockfd, "STARTTLS\r\n");
            if (!smtpReadResponse(sockfd, "220")) {
                throw std::runtime_error("STARTTLS命令失败");
            }
            
            std::cout << "开始SSL握手..." << std::endl;
            
            // 创建SSL上下文
            ssl_ctx_ = SSL_CTX_new(TLS_client_method());
            if (!ssl_ctx_) {
                throw std::runtime_error("创建SSL上下文失败");
            }
            
            // 创建SSL对象
            ssl_ = SSL_new(ssl_ctx_);
            if (!ssl_) {
                throw std::runtime_error("创建SSL对象失败");
            }
            
            // 将socket与SSL关联
            SSL_set_fd(ssl_, sockfd);
            
            // 进行SSL握手
            if (SSL_connect(ssl_) <= 0) {
                throw std::runtime_error("SSL握手失败");
            }
            
            std::cout << "SSL握手成功！" << std::endl;
            
            // 在SSL连接上重新发送EHLO
            sslSendCommand("EHLO localhost\r\n");
            if (!sslReadResponse("250")) {
                throw std::runtime_error("SSL EHLO命令失败");
            }
            
            // AUTH LOGIN
            sslSendCommand("AUTH LOGIN\r\n");
            if (!sslReadResponse("334")) {
                throw std::runtime_error("AUTH LOGIN命令失败");
            }
            
            // 用户名
            sslSendCommand(base64Encode(email_user_) + "\r\n");
            if (!sslReadResponse("334")) {
                throw std::runtime_error("用户名认证失败");
            }
            
            // 密码
            sslSendCommand(base64Encode(email_pass_) + "\r\n");
            if (!sslReadResponse("235")) {
                throw std::runtime_error("密码认证失败");
            }
                        
            // MAIL FROM
            sslSendCommand("MAIL FROM: <" + email_user_ + ">\r\n");
            if (!sslReadResponse("250")) {
                throw std::runtime_error("MAIL FROM命令失败");
            }
            
            // RCPT TO
            sslSendCommand("RCPT TO: <" + to_email + ">\r\n");
            if (!sslReadResponse("250")) {
                throw std::runtime_error("RCPT TO命令失败");
            }
            
            // DATA
            sslSendCommand("DATA\r\n");
            if (!sslReadResponse("354")) {
                throw std::runtime_error("DATA命令失败");
            }
            
            // 构造完整的邮件内容
            std::stringstream email_content;
            email_content << "From: " << sender_name_ << " <" << email_user_ << ">\r\n";
            email_content << "To: " << (to_name.empty() ? to_email : to_name + " <" + to_email + ">") << "\r\n";
            email_content << "Subject: " << subject << "\r\n";
            email_content << "Content-Type: text/plain; charset=utf-8\r\n";
            email_content << "\r\n";
            email_content << body << "\r\n";
            email_content << ".\r\n";  // 结束DATA
            
            sslSendCommand(email_content.str());
            if (!sslReadResponse("250")) {
                throw std::runtime_error("邮件内容发送失败");
            }
            
            // QUIT
            sslSendCommand("QUIT\r\n");
            sslReadResponse("221");
                        
        } catch (const std::exception& e) {
            LOG_ERROR("发送邮件失败: {}", e.what());
            close(sockfd);
            return false;
        }
        
        close(sockfd);
        return true;
    }

private:
    std::string base64Encode(const std::string& input) {
        std::string output;
        int val = 0, valb = -6;
        
        for (unsigned char c : input) {
            val = (val << 8) + c;
            valb += 8;
            while (valb >= 0) {
                output.push_back(base64_chars[(val >> valb) & 0x3F]);
                valb -= 6;
            }
        }
        
        if (valb > -6) {
            output.push_back(base64_chars[((val << 8) >> (valb + 8)) & 0x3F]);
        }
        
        while (output.size() % 4) {
            output.push_back('=');
        }
        
        return output;
    }

    bool smtpReadResponse(int sockfd, const std::string& expected_response) {
        char buffer[1024];
        int bytes_received = recv(sockfd, buffer, sizeof(buffer) - 1, 0);
        
        if (bytes_received > 0) {
            buffer[bytes_received] = '\0';
            std::string response(buffer);            
            if (response.find(expected_response) != std::string::npos) {
                return true;
            }
        }
        
        return false;
    }

    void smtpSendCommand(int sockfd, const std::string& command) {
        send(sockfd, command.c_str(), command.length(), 0);
    }

    bool sslReadResponse(const std::string& expected_response) {
        char buffer[1024];
        int bytes_received = SSL_read(ssl_, buffer, sizeof(buffer) - 1);
        
        if (bytes_received > 0) {
            buffer[bytes_received] = '\0';
            std::string response(buffer);
            
            if (response.find(expected_response) != std::string::npos) {
                return true;
            }
        }
        
        return false;
    }

    void sslSendCommand(const std::string& command) {
        SSL_write(ssl_, command.c_str(), command.length());
    }
};
}
#endif // EMAIL_VERIFICATION_H